﻿using System;
using System.Reflection;

using Moe.ECamel.Common.Contracts;

namespace Moe.ECamel.Client.ServiceProxies
{
	public abstract class ECamelServiceProxy<T> : IDisposable where T : class, IECamelService
	{
		/// <summary>
		/// Dynamic Reference to server side assembly.
		/// </summary>
		private static readonly Assembly _serverAssembly;
		/// <summary>
		/// Proxy to actual service implementation.
		/// </summary>
		protected T ServiceProxy;

		/// <summary>
		/// Static constructor.
		/// </summary>
		static ECamelServiceProxy()
		{
			// Load server assembly:
			_serverAssembly = Assembly.LoadFrom("Moe.ECamel.Server.dll");
		}

		/// <summary>
		/// Default constructor.
		/// </summary>
		protected ECamelServiceProxy()
			: this(GetServiceTypeNameByContractType(typeof(T)))
		{
		}

		private ECamelServiceProxy(String typeName)
		{
			// Load service interface type from server assembly:
			Type type = _serverAssembly.GetType(typeName);
			// Create instance of service interface:
			this.ServiceProxy = (T)Activator.CreateInstance(type);
		}

		/// <summary>
		/// Creates service type name from contract type.
		/// </summary>
		/// <param name="contractType">Contract type.</param>
		/// <returns></returns>
		private static String GetServiceTypeNameByContractType(Type contractType)
		{
			const String prefix = "I";

			// Get contract type name:
			String contractTypeName = contractType.Name;
			// Validate contract type name starts with standard prefix:
			if (!contractTypeName.StartsWith(prefix))
				throw new NotSupportedException("Cannot extract service type name from contract type because contract name does not start with prefix '"
					+ prefix + "'.");
			// Remove contract prefix to get service name:
			String serviceName = contractTypeName.Remove(0, prefix.Length);
			// Create service type name:
			String serviceTypeName = "Moe.ECamel.Server.Services." + serviceName;
			return serviceTypeName;
		}

		/// <summary>
		/// Release resources used by this component.
		/// </summary>
		public virtual void Dispose()
		{
			if (ServiceProxy != null)
			{
				ServiceProxy.Dispose();
				ServiceProxy = null;
			}
		}
	}
}